package br.edu.ufcg.ga.parser.args.group;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.ParseException;
import org.jgap.InvalidConfigurationException;

import br.edu.ufcg.ga.CVConfiguration;
import br.edu.ufcg.ga.population.InitialPopulationGenerator;
import br.edu.ufcg.ga.population.InitialPopulationGeneratorEnum;
import br.edu.ufcg.ga.population.InitialPopulationGeneratorFactory;

public class SimulationGroupBuilder implements MyGroupBuilder {

	//TODO Change elithism to elitism
	
	private Option SOpopSize;
	private Option SOmaxGenerations;
	private Option SOmaxRepetitionBestFitness;
	private Option SOcollectData;
	private Option SOoptimalValueStopCondition;
	private Option SOelithism;
	private Option SOinitialPopulationGenerator;
	private Option SOseed;

	public SimulationGroupBuilder() {
		init();
	}

	@SuppressWarnings("static-access")
	private void init() {
		SOpopSize = OptionBuilder.withDescription("Tamanho da população inicial").withLongOpt("SOpopSize").hasArgs(1)
				.withArgName("n").isRequired().create("SO_PS");
		SOmaxGenerations = OptionBuilder.withDescription("Quantidade máxima de gerações").withLongOpt(
				"SOmaxGenerations").hasArgs(1).withArgName("n").isRequired().create("SO_MG");
		SOmaxRepetitionBestFitness = OptionBuilder.withDescription("Repetição máxima do best fitness").withLongOpt(
				"SOmaxRepetitionBestFitness").hasArgs(1).withArgName("n").isRequired().create("SO_MRBF");
		SOcollectData = OptionBuilder.withDescription(
				"Devo coletar dados da execução (melhor fitness em cada geração, etc.)?").withLongOpt("SOcollectData")
				.hasArgs(1).withArgName("true/false").isRequired().create("SO_CD");
		SOoptimalValueStopCondition = OptionBuilder.withDescription(
				"Valor ótimo do PCV para ser usado na condição de parada ótima").withLongOpt(
				"SOoptimalValueStopCondition").hasArgs(1).withArgName("value").create("SO_OVSC");
		SOelithism = OptionBuilder.withDescription("Usar Elitismo?").withLongOpt("SOelithism").hasArgs(1).withArgName(
				"true/false").create("SO_E");
		SOinitialPopulationGenerator = OptionBuilder.withDescription("Como a população inicial deve ser inicializada?")
				.withLongOpt("SOinitialPopulationGenerator").hasArgs(1).withArgName("SIMPLE/RANDOM").create("SO_IPG");
		SOseed = OptionBuilder.withDescription("\"Seed\" inicial do gerador de números randômicos").withLongOpt(
				"SOseed").hasArgs(1).withArgName("seed").create("SO_S");
	}

	@Override
	public void config(CVConfiguration config, CommandLine commandLine) throws InvalidConfigurationException,
			ParseException {
		int popSize = getPopSize(commandLine);
		int maxGenerations = getMaxGenerations(commandLine);
		int maxRepetitionBestFitness = getMaxRepetitionBestFitness(commandLine);
		boolean collectData = getCollectData(commandLine);
		Double optimalValueStopCondition = getOptimalValueStopCondition(commandLine);
		boolean elithism = getElithism(commandLine);
		InitialPopulationGenerator initialPopulationGenerator = getInitialPopulationGenerator(commandLine);
		long seed = getSeed(commandLine);

		config.setPopSize(popSize);
		config.setMaxGenerations(maxGenerations);
		config.setMaxRepetitionBestFitness(maxRepetitionBestFitness);
		config.setCollectData(collectData);
		config.setOptimalValueStopCondition(optimalValueStopCondition);
		config.setElithism(elithism);
		config.setInitialPopulationGenerator(initialPopulationGenerator);
		config.setSeed(seed);
	}

	private long getSeed(CommandLine commandLine) {
		String seedString = getOptionValue(SOseed, commandLine);
		return seedString == null ? System.currentTimeMillis() : Long.parseLong(seedString);
	}

	private InitialPopulationGenerator getInitialPopulationGenerator(CommandLine commandLine) {
		String initialPopulationGeneratorString = getOptionValue(SOinitialPopulationGenerator, commandLine);
		if (initialPopulationGeneratorString == null) {
			// This option is not required. Default initial population generator is RANDOM
			initialPopulationGeneratorString = InitialPopulationGeneratorEnum.RANDOM.name();
		}
		return InitialPopulationGeneratorFactory.getInitialPopulationGenerator(initialPopulationGeneratorString);
	}

	private boolean getElithism(CommandLine commandLine) {
		String elithismString = getOptionValue(SOelithism, commandLine);
		// This option is not required. Default is USE elithism
		return elithismString != null ? Boolean.parseBoolean(elithismString) : true;
	}

	private Double getOptimalValueStopCondition(CommandLine commandLine) {
		String optimalValueStopConditionString = getOptionValue(SOoptimalValueStopCondition, commandLine);
		return optimalValueStopConditionString != null ? Double.parseDouble(optimalValueStopConditionString) : null;
	}

	private boolean getCollectData(CommandLine commandLine) {
		String collectDataString = getOptionValue(SOcollectData, commandLine);
		return Boolean.parseBoolean(collectDataString);
	}

	private int getMaxRepetitionBestFitness(CommandLine commandLine) {
		String maxRepetitionBestFitnessString = getOptionValue(SOmaxGenerations, commandLine);
		return Integer.parseInt(maxRepetitionBestFitnessString);
	}

	private int getMaxGenerations(CommandLine commandLine) {
		String maxGenerationsString = getOptionValue(SOmaxGenerations, commandLine);
		return Integer.parseInt(maxGenerationsString);
	}

	private int getPopSize(CommandLine commandLine) {
		String popSizeString = getOptionValue(SOpopSize, commandLine);
		return Integer.parseInt(popSizeString);
	}

	@Override
	public Option[] getOptions() {
		return new Option[] {
								SOpopSize, SOmaxGenerations, SOmaxRepetitionBestFitness, SOcollectData,
								SOoptimalValueStopCondition, SOelithism, SOinitialPopulationGenerator, SOseed };
	}

	protected String getOptionValue(Option option, CommandLine commandLine) {
		String s = commandLine.getOptionValue(option.getOpt());
		if (s == null) {
			s = commandLine.getOptionValue(option.getLongOpt());
		}
		return s;
	}

}
